from ..catalog.entry import catalog_table, catalog_index

def table_tuple_get_all(table_name: str):
    # 断言一般用于调试，断言失败，程序就会终止
    # 生产不应该使用断言，因为断言失败，程序就会终止，应该要返回错误

    # 如果该函数的所有调用接口，都能确保传递进来的参数 table_name 是有意义的，那么此函数内部就不需要重复判断了
    tables = catalog_table.select(lambda r: r.table_name == table_name)
    assert len(tables) > 0
    for location in table_tuple_get_locations(table_name):
        yield table_tuple_get_one(table_name, location)

mock_table_data = {
    't1': [
        (1,'小明'),
        (2,'小红'),
        (3,'小刚'),
        (4,'小丽')
    ],
    't2': [
        (1,'明小','北京'),
        (2,'红柒','上海'),
        (3,'刚营','广州'),
        (4,'丽江','云南')
    ],
    't3': [
        (1,'北京','朝阳'),
        (2,'上海','浦东'),
        (3,'广州','天河'),
    ],
    't4': [
        (2, 'google', 'beckend'),
        (3, 'meta', 'frontend'),
        (5, 'aws', 'sales')
    ]
}

def table_tuple_get_locations(table_name: str):
    if table_name == 't1':
        return [0,1,2,3]
    elif table_name == 't2':
        return [0,1,2,3]
    elif table_name == 't3':
        return [0,1,2]
    elif table_name == 't4':
        return [0,1,2]
    else:
        return

def table_tuple_get_one(table_name: str, location: int):
    return mock_table_data[table_name][location]

mock_idx = {
    # python 的元组天然支持比较，所以这里可以用元组作为索引的 key
    # 该索引的 key 是t1的id的列的具体值，这里用元组，是表示列可能有多行，即联合索引
    # 该索引的 value 是该行元组在原始表数据中的逻辑位置(location)，这里使用列表，是因为可能有多行元组对应同一个key
    'idx': {
        (1,): [0],
        (2,): [1],
        (3,): [2],
        (4,): [3]
    }
}

def index_tuple_get_range_locations(index_name: str, start=(float('-inf'),), end=(float('-inf'),)):
    for key in mock_idx[index_name]:
        if range_compare(key, start, end):
            locations = mock_idx[index_name][key]
            for location in locations:
                yield location


def index_tuple_get_range(index_name: str, start=None, end=None):
    """
    start和end两个参数，是用来指定扫描索引中的部分数据的，如果不给这两个参数赋值
    那么，就默认拿这个索引中的全部数据 
    """

    table_name = get_table_name_from_index_name(index_name)
    for location in index_tuple_get_range_locations(index_name, start, end):
        # 该过程就是**回表**过程，即全量表数据中获取location的部分
        yield table_tuple_get_one(table_name, location)


def index_tuple_get_equal_value(index_name: str, equal_value):
    table_name = get_table_name_from_index_name(index_name)
    for location in mock_idx[index_name][equal_value]:
        yield table_tuple_get_one(table_name, location)


def covered_index_tuple_get_range(index_name: str, start=None, end=None):
    for key in mock_idx[index_name]:
        if range_compare(key, start, end):
            locations = mock_idx[index_name][key]
            # covered index 没有回表过程，这就是 coverd 的含义
            # 也是 IndexOnlyScan 中的Only的意思
            for _ in locations:
                yield key
            
def covered_index_tuple_get_equal_value(index_name: str, equal_value):
    for _ in mock_idx[index_name][equal_value]:
        yield equal_value

def get_table_name_from_index_name(index_name: str):
    results = catalog_index.select(lambda r: r.index_name == index_name)
    table_name = results[0].table_name
    return table_name

def range_compare(key: tuple[float], start=None, end=None):
    if not start and not end:
        return False
    elif start and not end:
        return key > start
    elif not start and end:
        return key < end
    elif start < key < end:
        return True
    else:
        return False